#ifndef RENDERTREE_H_
#define RENDERTREE_H_

#include "include/dto/3d/matrix.h"
#include <QObject>
#include <QList>
#include <QHash>
#include <QGLWidget>
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#include "window.h"

class AbstractRenderTree {
public:
	AbstractRenderTree(){}
	virtual ~AbstractRenderTree(){}
	virtual void render(QGLWidget *gl,Renderable *o)=0;
};

class Renderer {
	public:
	Renderer();
	virtual ~Renderer();
	virtual void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r)=0;
};

class RenderTree : public AbstractRenderTree {

	public:
	RenderTree();
	~RenderTree();
	void render(QGLWidget *gl,std::list<Renderable*> *list);
	void render(QGLWidget *gl,Renderable *o);
	void addRenderer(std::string name,Renderer *r);

	private:
	std::map<std::string, Renderer *> rendererMap;

};

class RotateRenderer : public Renderer{
	public:
	RotateRenderer();
	~RotateRenderer();
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
};

class TranslateRenderer : public Renderer{
	public:
	TranslateRenderer();
	~TranslateRenderer();
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
};

class TextureRenderer : public Renderer{
	public:
	TextureRenderer();
	~TextureRenderer();
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
	private:
	QImage *pic;
	GLuint texture;
};

class MovieRenderer : public Renderer{
	public:
	MovieRenderer();
	~MovieRenderer();

	bool GetNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx,
			    int videoStream, AVFrame *pFrame,Texture *t,int frameDiff);
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
	int load(std::string name,int start,int playMode);
	private:
		AVFormatContext *pFormatCtx;
		int             i, videoStream,counter;
		AVCodecContext  *pCodecCtx;
		AVCodec         *pCodec;
		AVFrame         *pFrame;
		AVFrame         *pFrameRGB;
		AVFrame         *dst;
		int             numBytes;
		uint8_t         *buffer;
		uint8_t         *dstbuffer;
		uint8_t         *alpha;
		GLuint texture;
		long lastTime;
		bool inited;
		float lastCurrent;
		int lastFileNum;
		int lastSize;
		int pid;
		bool reset;
		std::string lastFileName;
};

class MovieRendererDelegate : public Renderer {
public:
	MovieRendererDelegate();
	~MovieRendererDelegate();
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
private:
	std::map<Renderable*, MovieRenderer *> rendererMap;
};

class DiamondRenderer : public Renderer{
	public:
	DiamondRenderer();
	~DiamondRenderer();
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
};

class RectangleRenderer : public Renderer{
	public:
	RectangleRenderer();
	~RectangleRenderer();
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r);
};

class VideoDisplayRenderer : public Renderer {
public:
	VideoDisplayRenderer(){}
	~VideoDisplayRenderer(){}
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r) {
		VideoDisplay *display = (VideoDisplay*)o;
		r->render(gl,display->pos->get());
//		r->render(gl,display->preview->get());
		if (IsControl::control()) {
			r->render(gl,display->source1->get());
			r->render(gl,display->source2->get());
			r->render(gl,display->source3->get());
			r->render(gl,display->source4->get());
		}
	}
};

class DisplayPanelRenderer : public Renderer {
public:
	DisplayPanelRenderer(){}
	~DisplayPanelRenderer(){}
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r) {
		DisplayPanel *display = (DisplayPanel*)o;
		if (display->render->get()==0)
			return;
		glPushMatrix();

		r->render(gl,display->pos->get());
		r->render(gl,display->rot->get());
		r->render(gl,display->text->get());
		r->render(gl,display->rect->get());
		glPopMatrix();
	}
};

class BodyRenderer : public Renderer{
private:
	Walker *w;
	public:
	BodyRenderer(){
		w=0;
	}
	~BodyRenderer(){}
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r){
		Body *body = (Body*)o;
		if (w==0) {
			w=new Walker(body);
		}
		w->nextStep();
		r->render(gl,body->pos->get());
		r->render(gl,body->rot->get());
		r->render(gl,body->torso->get());
		r->render(gl,body->leftArm->get());
		r->render(gl,body->rightArm->get());
		r->render(gl,body->leftLeg->get());
		r->render(gl,body->rightLeg->get());
	}
};

class ExtremityRenderer : public Renderer{
	public:
	ExtremityRenderer(){}
	~ExtremityRenderer(){}
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r){
		Extremity *ex = (Extremity*)o;
		glPushMatrix();
		r->render(gl,ex->pos->get());
		r->render(gl,ex->upper->get());
		r->render(gl,ex->lower->get());
		r->render(gl,ex->end->get());
		glPopMatrix();
	}
};

class LimbRenderer : public Renderer{
	public:
	LimbRenderer(){}
	~LimbRenderer(){}
	void render(QGLWidget *gl,Renderable *o,AbstractRenderTree *r){
		Limb *limb = (Limb*)o;
		r->render(gl,limb->trans->get());
		r->render(gl,limb->rot->get());
		r->render(gl,limb->rect->get());
	}
};

#endif /*RENDERTREE_H_*/
